/*************************************************************************/
/**	WordlistGenerator is a program that dynamically generates 			**/
/**		wordlists based on certain ASCII character sets that are 		**/
/**		chosen by the user.												**/
/**																		**/
/**	@author dot_Cipher													**/
/**	Copyright under the GNU Public License v3 2011						**/
/*************************************************************************/

// VERSION: 1.8
#include <stdio.h>s
#include <stdlib.h>
#include <string.h>

void loadOutput(char password[], char *fileName, FILE *fileToLoad){
	FILE *parsedFile;
	char temp[65];
	temp[0] = '\0';
	parsedFile = fopen("wordlistgen_temp.txt", "w");
	rewind(fileToLoad);
	fscanf(fileToLoad, "%s", temp);
	printf("%s \n", "Loading from saved output...");
	while(strcmp(password, temp) != 0){
		fprintf(parsedFile, "%s\n", temp);
		fscanf(fileToLoad, "%s", temp);
	}
	fclose(fileToLoad);
	fclose(parsedFile);
	if(remove(fileName) != 0) perror("Error deleting file.");
	if(rename("wordlistgen_temp.txt", fileName) == -1) perror("Error renaming file.");
}

int main(int argc, char *argv[]){
	FILE *output;
	FILE *log;
	char numSet[11] = "0123456789";  // + null term
	char upperSet[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";  // + n ull term
	char lowerSet[27] = "abcdefghijklmnopqrstuvwxyz";  // + null term
	char specialSet[33] = "!\"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~";  // + null term
	char charSet[96];	// Max char set if every ASCII char is used + null term
	char password[65];	// Max 64 characters + null term
	char endword[65];	// Max 64 characters + null term
	char *customStr;
	char *path;
	int min, max, i, j, k, numPass, saveType, loadBool;
	int setsBool[6] = {0,0,0,0,0,0}; 
	// 0=custom, 1=lower, 2=upper, 3=num, 4=special, 5=space
	int shift[255];
	saveType = loadBool = 0;
	i = j = k = numPass = 0;
	min = max = 6;
	charSet[0] = '\0';

	// CHECK CONSOLE INPUT:
	for(i=1; i<argc; i++){
		if(strcmp(argv[i], "-min") == 0)	min = atoi(argv[i+1]);
		if(strcmp(argv[i], "-max") == 0)	max = atoi(argv[i+1]);
		if(strcmp(argv[i], "-a") == 0)		setsBool[1] = 1;
		if(strcmp(argv[i], "-A") == 0)		setsBool[2] = 1;
		if(strcmp(argv[i], "-n") == 0)		setsBool[3] = 1;
		if(strcmp(argv[i], "-u") == 0)		setsBool[4] = 1;
		if(strcmp(argv[i], "-s") == 0)		setsBool[5] = 1;
		if(strcmp(argv[i], "-c") == 0){
			setsBool[0] = 1;
			customStr = argv[i+1];
		}
		if(strcmp(argv[i], "-o") == 0){
				path = (char *)malloc(sizeof(argv[i+1]));
				path = argv[i+1];
				output = fopen(path, "a+");
				saveType = 1;
		}
		if(strcmp(argv[i], "-x") == 0){
			saveType = 2;
		}
		if(strcmp(argv[i], "-L") == 0){
			log = fopen("wordlist_log.txt", "r+");
			if(log == NULL)
				printf("%s \n", "No log file found, starting new wordlist generation...");
			else{
				path = (char *)malloc(512);
				fscanf(log, "%s", path);
				fscanf(log, "%s", charSet);
				fscanf(log, "%s", password);
				fscanf(log, "%d", &min);
				fscanf(log, "%d", &max);
				fclose(log);
				output = fopen(path, "a+");
				loadBool = 1;
				loadOutput(password, path, output);
				output = fopen(path, "a+");
				saveType = 1;
			}
		}
		if (strcmp(argv[i],"-h")==0){
			printf("%s \n","Wordlist Generator v1.8 by dot_Cipher");
			printf("%s \n","Copyright (c) under GNU PL v3 2011");
			printf("%s \n","Usage: ./wordlistgen [options]");
			printf("%s \n","FILE I/O:");
			printf("%s \n","   -S [session]	: save output session (no spaces) [default: newlist]");
			printf("%s \n","   -L [session]	: load from previous output of session");
			printf("%s \n","   -o [path]	: output path for saving wordlist [default: ./wordlist.txt]");
			printf("%s \n","   -x			: exclude saving to file (for only piping to stdout)");
			printf("%s \n","WORDLIST OUTPUT:");
			printf("%s \n","   -c [string]	: use custom [string] as character set");
			printf("%s \n","   -min			: minimum string output length [default is 6]");
			printf("%s \n","   -max			: maximum string output length [default is 6]");
			printf("%s \n","   -a			: use lower-case letters (a-z) [default]");
			printf("%s \n","   -A			: use upper-case letters (A-Z)");
			printf("%s \n","   -n			: use decimal numbers (0-9)");
			printf("%s \n","   -u			: use unique characters (!#$%& ...)");
			printf("%s \n","   -s			: use the space character ( )");
			printf("%s \n","MISC:");
			printf("%s \n","   -h			: show help screen (you are looking at it)");
			exit(0);
		}
	}
	// Creates untitled wordlist if saveType is 0
	if(saveType == 0 && loadBool != 1){
		path = "wordlist.txt";
		output = fopen(path, "a+");
		saveType = 1;
	}
	// Create character set from input bools
	// 0=custom, 1=lower, 2=upper, 3=num, 4=special, 5=space
	// priority to custom string
	if(setsBool[0]==1){
		k = strlen(customStr);
		for(j=0; j<k; j++){
			charSet[j] = *customStr;
			charSet[j+1] = '\0';
			customStr++;
		}
	}
	else{
		j=0;
		if(setsBool[1]==1){
			i=strlen(lowerSet);
			for(k=0; k<=i; k++){
				charSet[j] = lowerSet[k];
				charSet[j+1] = '\0';
				j++;
			}j--;
		}
		if(setsBool[2]==1){
			i=strlen(upperSet);
			for(k=0; k<=i; k++){
				charSet[j] = upperSet[k];
				charSet[j+1] = '\0';
				j++;
			}j--;
		}
		if(setsBool[3]==1){
			i=strlen(numSet);
			for(k=0; k<=i; k++){
				charSet[j] = numSet[k];
				charSet[j+1] = '\0';
				j++;
			}j--;
		}
		if(setsBool[4]==1){
			i=strlen(specialSet);
			for(k=0; k<=i; k++){
				charSet[j] = specialSet[k];
				charSet[j+1] = '\0';
				j++;
			}j--;
		}
		if(setsBool[5]==1){
			charSet[j] = ' ';
			charSet[j+1] = '\0';
			j++;
		}j--;
	}

	// Lock max if invalid input given
	if(max<min) max=min;
	if(strcmp(charSet, "\0") == 0){
		strcpy(charSet, lowerSet);
		i=26;
	}
	else{
		i=strlen(charSet);
	}
	i=i-1;
	for(j=0; j<=i; j++){
		shift[charSet[j]]=j;
	}
	min=min-1;
	max=max-1;
	for(j=min; j<=max; j++){
		if(loadBool==0){
			password[0] = '\0';
			for(k=0;k<=j;k++){
				password[k] = charSet[0];
				password[k+1] = '\0';
			}
		}
		loadBool=0;
		endword[0] = '\0';
		for(k=0; k<=j; k++){
			endword[k] = charSet[i];
			endword[k+1] = '\0';
		}
		while(strcmp(password, endword) != 0){
			numPass++;
			for(k=0; k<=j; k++){
				if(password[j-k] == (charSet[i+1])){
					password[j-k] = charSet[0];
					password[j-1-k] = charSet[shift[password[j-1-k]]+1];
				}
			}
			printf("%s \n", password);
			if(numPass%10000==1){
				log = fopen("wordlist_log.txt", "w+");
				fprintf(log, "%s\n", path);
				fprintf(log, "%s\n", charSet);
				fprintf(log, "%s\n", password);
				fprintf(log, "%d\n", j+1);
				fprintf(log, "%d\n", max+1);
				fclose(log);
			}
			if(saveType==1) fprintf(output, "%s\n", password);
			password[j] = charSet[shift[password[j]]+1];
			// Check if last password
			if(strcmp(password, endword) == 0){
				numPass++;
				for(k=0; k<=j; k++){
					if(password[j-k] == (charSet[i+1])){
						password[j-k] = charSet[0];
						password[j-1-k] = charSet[shift[password[j-1-k]]+1];
					}
				}
				printf("%s \n", password);
				if(numPass%10000==1){
					log = fopen("wordlist_log.txt", "w+");
					fprintf(log, "%s\n", path);
					fprintf(log, "%s\n", charSet);
					fprintf(log, "%s\n", password);
					fprintf(log, "%d\n", j+1);
					fprintf(log, "%d\n", max+1);
					fclose(log);
				}
				if(saveType==1) fprintf(output, "%s\n", password);
			}
		}
	}
	if(saveType==1) fclose(output);
	return 0;
}